#include <WinSock2.h>
#include <errno.h>
#include <utils.h>

#if !defined(ECURDIR)
#define ECURDIR EACCES
#endif
#if !defined(ENOSYS)
#define ENOSYS EPERM
#endif

typedef struct ERRMAP_T
{
	unsigned long w32Err;
	int eerrno;
}ErrMap;

static const ErrMap errmap[] = 
{
	{ ERROR_INVALID_FUNCTION, EINVAL },
	{ ERROR_FILE_NOT_FOUND, ENOENT },
	{ ERROR_PATH_NOT_FOUND, ENOENT },
	{ ERROR_TOO_MANY_OPEN_FILES, EMFILE },
	{ ERROR_ACCESS_DENIED , EACCES },
	{ ERROR_INVALID_HANDLE , EBADF },
	{ ERROR_ARENA_TRASHED , ENOMEM },
	{ ERROR_NOT_ENOUGH_MEMORY , ENOMEM },
	{ ERROR_INVALID_BLOCK , ENOMEM },
	{ ERROR_BAD_ENVIRONMENT , E2BIG },
	{ ERROR_BAD_FORMAT , ENOEXEC },
	{ ERROR_INVALID_ACCESS , EINVAL },
	{ ERROR_INVALID_DATA , EINVAL },
	{ ERROR_OUTOFMEMORY , ENOMEM },
	{ ERROR_INVALID_DRIVE , ENOENT },
	{ ERROR_CURRENT_DIRECTORY , ECURDIR },
	{ ERROR_NOT_SAME_DEVICE , EXDEV },
	{ ERROR_NO_MORE_FILES , ENOENT },
	{ ERROR_WRITE_PROTECT , EROFS },
	{ ERROR_BAD_UNIT , ENXIO },
	{ ERROR_NOT_READY, EBUSY },
	{ ERROR_BAD_COMMAND , EIO },
	{ ERROR_CRC , EIO },
	{ ERROR_BAD_LENGTH , EIO },
	{ ERROR_SEEK , EIO },
	{ ERROR_NOT_DOS_DISK , EIO },
	{ ERROR_SECTOR_NOT_FOUND, ENXIO },
	{ ERROR_OUT_OF_PAPER , EBUSY },
	{ ERROR_WRITE_FAULT , EIO },
	{ ERROR_READ_FAULT , EIO },
	{ ERROR_GEN_FAILURE , EIO },
	{ ERROR_SHARING_VIOLATION , EAGAIN },
	{ ERROR_LOCK_VIOLATION , EACCES },
	{ ERROR_WRONG_DISK , ENXIO },
	{ 35, ENFILE },
	{ ERROR_SHARING_BUFFER_EXCEEDED , ENFILE },
	{ ERROR_HANDLE_EOF , EINVAL },
	{ ERROR_HANDLE_DISK_FULL, ENOSPC },
	{ ERROR_NOT_SUPPORTED , ENOSYS },
	{ ERROR_BAD_NETPATH , ENOENT },
	{ ERROR_NETWORK_ACCESS_DENIED , EACCES },
	{ ERROR_BAD_NET_NAME , ENOENT },
	{ ERROR_FILE_EXISTS , EEXIST },
	{ ERROR_CANNOT_MAKE , EACCES },
	{ ERROR_FAIL_I24 , EACCES },
	{ ERROR_INVALID_PARAMETER , EINVAL },
	{ ERROR_NO_PROC_SLOTS , EAGAIN },
	{ ERROR_DRIVE_LOCKED , EACCES },
	{ ERROR_BROKEN_PIPE , EPIPE },
	{ ERROR_BUFFER_OVERFLOW , ENAMETOOLONG },
	{ ERROR_DISK_FULL, ENOSPC },
	{ ERROR_INVALID_TARGET_HANDLE , EBADF },
	{ ERROR_INVALID_NAME , ENOENT },
	{ ERROR_INVALID_HANDLE , EINVAL },
	{ ERROR_WAIT_NO_CHILDREN, ECHILD },
	{ ERROR_CHILD_NOT_COMPLETE , ECHILD },
	{ ERROR_DIRECT_ACCESS_HANDLE , EBADF },
	{ ERROR_NEGATIVE_SEEK , EINVAL },
	{ ERROR_SEEK_ON_DEVICE , EACCES },
	{ ERROR_DIR_NOT_EMPTY , ENOTEMPTY },
	{ ERROR_NOT_LOCKED , EACCES },
	{ ERROR_BAD_PATHNAME , ENOENT },
	{ ERROR_MAX_THRDS_REACHED , EAGAIN },
	{ ERROR_LOCK_FAILED , EACCES },
	{ ERROR_ALREADY_EXISTS , EEXIST },
	{ ERROR_FILENAME_EXCED_RANGE , ENAMETOOLONG },
	{ ERROR_NESTING_NOT_ALLOWED, EAGAIN },
	{ ERROR_DIRECTORY, ENOTDIR },
#ifdef EINPROGRESS
	{ ERROR_IO_PENDING , EINPROGRESS },
#else
	{ ERROR_IO_PENDING , EBUSY },
#endif
	{ ERROR_NOT_ENOUGH_QUOTA, ENOMEM }
};

int Errno_From_Win32(unsigned long w32Err)
{
	size_t i;
	for(i = 0; i < NUM_ELEMENTS(errmap); ++i)
	{
		if(w32Err == errmap[i].w32Err)
		{
			return errmap[i].eerrno;
		}
	}
	return EINVAL;
}

void* Win32_Handle_From_File(int fd)
{
	union
	{
		HANDLE h;
		long i;
	} u;

	if(fd < 0)
	{
		return INVALID_HANDLE_VALUE;
	}
	else
	{
		u.h = NULL;
		u.i = _get_osfhandle(fd);

		return u.h;
	}
}

long sysconf(int name)
{ 
	SYSTEM_INFO info; 
	GetSystemInfo(&info);
	return info.dwNumberOfProcessors;
}

void initsocket(void){
	WORD version;
	WSADATA wsaData;
	version = MAKEWORD(2,2);
	WSAStartup(version, &wsaData);
}